namespace EasyNetQ;

public interface IMessage<out T> : IMessage
{
    /// <summary>
    /// The message body as a .NET type.
    /// This will return the same underlying object than <see cref="IMessage.GetBody"/> but will be strongly typed.
    /// </summary>
    T? Body { get; }
}

public interface IMessage
{
    /// <summary>
    /// The message properties.
    /// </summary>
    MessageProperties Properties { get; }

    /// <summary>
    /// The message body return as an object when we only have runtime types and can't use generics.
    /// </summary>
    object? GetBody();

    /// <summary>
    /// The message <see cref="Type"/>. This is a shortcut to GetBody().GetType().
    /// </summary>
    Type MessageType { get; }
}

public class Message<T> : IMessage<T>
{
    public MessageProperties Properties { get; }
    public Type MessageType { get; }
    public T? Body { get; }

    public object? GetBody() { return Body; }

    public Message(T? body)
    {
        Body = body;
        Properties = MessageProperties.Empty;
        MessageType = body != null ? body.GetType() : typeof(T);
    }

    public Message()
    {
        Body = default;
        Properties = default;
        MessageType = typeof(T);
    }

    public Message(T? body, in MessageProperties properties)
    {
        Body = body;
        Properties = properties;
        MessageType = body != null ? body.GetType() : typeof(T);
    }
}
